﻿/***********************************************************
Copyright © 2015 Howyoung.
************************************************************
You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty.
************************************************************
您可以对所收受的本程序源代码，无论以何种媒介，复制与发布其完
整的复制物，然而您必须以显著及适当的方式在每一份复制物上发布
适当的著作权标示及无担保声明。
***********************************************************/
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Windows.Forms;

namespace MinecraftSavesBackup
{
    public partial class ViewBackups : Form
    {
        public StringCollection savesList = new StringCollection();
        public string backupAddress = null;

        public ViewBackups()
        {
            InitializeComponent();
        }

        private void recoveryPictureBox_MouseEnter(object sender, EventArgs e)
        {
            recoveryPictureBox.Image = Properties.Resources.recoveryGray;
        }

        private void deletePictureBox_MouseEnter(object sender, EventArgs e)
        {
            deletePictureBox.Image = Properties.Resources.deleteGray;
        }

        private void inputPictureBox_MouseEnter(object sender, EventArgs e)
        {
            inputPictureBox.Image = Properties.Resources.inputGray;
        }

        private void outputPictureBox_MouseEnter(object sender, EventArgs e)
        {
            outputPictureBox.Image = Properties.Resources.outputGray;
        }

        private void recoveryPictureBox_MouseLeave(object sender, EventArgs e)
        {
            recoveryPictureBox.Image = Properties.Resources.recoveryWhite;
        }

        private void deletePictureBox_MouseLeave(object sender, EventArgs e)
        {
            deletePictureBox.Image = Properties.Resources.deleteWhite;
        }

        private void inputPictureBox_MouseLeave(object sender, EventArgs e)
        {
            inputPictureBox.Image = Properties.Resources.inputWhite;
        }

        private void outputPictureBox_MouseLeave(object sender, EventArgs e)
        {
            outputPictureBox.Image = Properties.Resources.outputWhite;
        }

        private double GetDirectorySize(string directoryName)
        {
            double size = 0;
            DirectoryInfo directory = new DirectoryInfo(directoryName);
            //遍历文件
            foreach (FileInfo files in directory.GetFiles("*", SearchOption.AllDirectories))
            {
                size = size + files.Length;
            }
            size = Convert.ToDouble(decimal.Round(Convert.ToDecimal(size / 1024 / 1024), 2));//换算为MB,保留2位小数
            return size;
        }

        private void RefreshInfo()
        {
            //加载备份
            try
            {
                int index = backupListBox.SelectedIndex;
                string dirPath = Properties.Settings.Default.BackupAddress;
                List<string> dirs = new List<string>(Directory.EnumerateDirectories(dirPath));
                backupListBox.Items.Clear();
                foreach (string folder in dirs)
                {
                    backupListBox.Items.Add(folder.Substring(folder.LastIndexOf("\\") + 1));
                }
                if (index < backupListBox.Items.Count - 1) backupListBox.SelectedIndex = index;
                savesCheckedListBox.Items.Clear();
                if (backupListBox.SelectedIndex == -1)
                {
                    backupSizeLabel.Text = "备份大小：(选择一个备份)";
                }
                else
                {
                    //加载存档
                    DirectoryInfo folder = new DirectoryInfo(Properties.Settings.Default.BackupAddress + backupListBox.SelectedItem.ToString());
                    foreach (FileInfo file in folder.GetFiles("*.*"))
                    {
                        savesCheckedListBox.Items.Add(file.Name);
                    }
                    backupSizeLabel.Text = "备份大小：" + Convert.ToString(GetDirectorySize(Properties.Settings.Default.BackupAddress + backupListBox.SelectedItem.ToString())) + " MB";
                }
                backupNumberLabel.Text = "备份数量：" + Convert.ToString(backupListBox.Items.Count) + " 个";
                allSizeLabel.Text = "备份总大小：" + Convert.ToString(GetDirectorySize(Properties.Settings.Default.BackupAddress)) + " MB";
            }
            catch (Exception ex)
            {
                HandlingErrors.ErrorMessage(ex, "关闭窗口并重新进入。");
                HandlingErrors.Record(ex);
            }
        }

        private void ViewBackups_Shown(object sender, EventArgs e)
        {
            RefreshInfo();
        }

        private void backupListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                savesCheckedListBox.Items.Clear();
                if (backupListBox.SelectedIndex == -1)
                {
                    backupSizeLabel.Text = "备份大小：(选择一个备份)";
                }
                else
                {
                    //加载存档
                    DirectoryInfo folder = new DirectoryInfo(Properties.Settings.Default.BackupAddress + backupListBox.SelectedItem.ToString());
                    foreach (FileInfo file in folder.GetFiles("*.*"))
                    {
                        savesCheckedListBox.Items.Add(file.Name);
                    }
                    backupSizeLabel.Text = "备份大小：" + Convert.ToString(GetDirectorySize(Properties.Settings.Default.BackupAddress + backupListBox.SelectedItem.ToString())) + " MB";
                }
            }
            catch (Exception)
            { }
        }

        private void Filter()
        {
            try
            {
                //按日期筛选
                //处理日期
                string fromYear, fromMonth, fromDay, fromHour, fromMinute, fromSecond;
                fromYear = Convert.ToString(fromDatePicker.Value.Year);
                fromMonth = Convert.ToString(fromDatePicker.Value.Month);
                fromDay = Convert.ToString(fromDatePicker.Value.Day);
                fromHour = Convert.ToString(fromTimePicker.Value.Hour);
                fromMinute = Convert.ToString(fromTimePicker.Value.Minute);
                fromSecond = Convert.ToString(fromTimePicker.Value.Second);
                if (fromMonth.Length == 1) fromMonth = "0" + fromMonth;
                if (fromDay.Length == 1) fromDay = "0" + fromDay;
                if (fromHour.Length == 1) fromHour = "0" + fromHour;
                if (fromMinute.Length == 1) fromMinute = "0" + fromMinute;
                if (fromSecond.Length == 1) fromSecond = "0" + fromSecond;
                string from = fromYear + fromMonth + fromDay + fromHour + fromMinute + fromSecond;

                string toYear, toMonth, toDay, toHour, toMinute, toSecond;
                toYear = Convert.ToString(toDatePicker.Value.Year);
                toMonth = Convert.ToString(toDatePicker.Value.Month);
                toDay = Convert.ToString(toDatePicker.Value.Day);
                toHour = Convert.ToString(toTimePicker.Value.Hour);
                toMinute = Convert.ToString(toTimePicker.Value.Minute);
                toSecond = Convert.ToString(toTimePicker.Value.Second);
                if (toMonth.Length == 1) toMonth = "0" + toMonth;
                if (toDay.Length == 1) toDay = "0" + toDay;
                if (toHour.Length == 1) toHour = "0" + toHour;
                if (toMinute.Length == 1) toMinute = "0" + toMinute;
                if (toSecond.Length == 1) toSecond = "0" + toSecond;
                string to = toYear + toMonth + toDay + toHour + toMinute + toSecond;

                long iFrom = Convert.ToInt64(from), iTo = Convert.ToInt64(to);
                if (iFrom < iTo)
                {
                    //刷新列表
                    RefreshInfo();
                    StringCollection backupNames = new StringCollection();
                    foreach (string item in backupListBox.Items)
                    {
                        //判断时间是否在规定范围内
                        if (Convert.ToInt64(item) >= iFrom && Convert.ToInt64(item) <= iTo)
                        {
                            backupNames.Add(item);
                        }
                    }
                    backupListBox.Items.Clear();
                    foreach (var backupName in backupNames)
                    {
                        backupListBox.Items.Add(backupName);
                    }
                }
                else
                {
                    MessageBox.Show("请选择正确的日期。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
            }
            catch (Exception)
            { }
        }

        private void OKlabel_Click(object sender, EventArgs e)
        {
            Filter();
        }

        private void fromDatePicker_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter) Filter();
        }

        private void searchPictureBox_Click(object sender, EventArgs e)
        {
            savesCheckedListBox.SelectedIndex = savesCheckedListBox.FindString(searchTextBox.Text);
        }

        private void searchTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter) savesCheckedListBox.SelectedIndex = savesCheckedListBox.FindString(searchTextBox.Text);
        }

        private void recoveryPictureBox_Click(object sender, EventArgs e)
        {
            if (savesCheckedListBox.CheckedItems.Count == 0)
            {
                MessageBox.Show("请选择要恢复的存档。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else
            {
                recoveryPictureBox.Visible = false;
                recoveryingLabel.Text = "0%";
                recoveryingLabel.Visible = true;

                savesList.Clear();
                foreach (string save in savesCheckedListBox.CheckedItems)
                {
                    savesList.Add(save);
                }
                backupAddress = Properties.Settings.Default.BackupAddress + backupListBox.SelectedItem;
                if (!backupAddress.EndsWith("\\")) backupAddress += "\\";
                backgroundWorker.RunWorkerAsync();
            }
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            double count = 0;
            double all = savesList.Count;

            //恢复存档
            try
            {
                foreach (string save in savesList)
                {
                    string saveAddress = Properties.Settings.Default.SaveAddress + save.Replace(".saves", null);
                    string backupFileAddress = backupAddress + save;
                    if (Directory.Exists(save)) Directory.Delete(saveAddress);
                    Compression.DecompressZip(backupFileAddress, saveAddress);
                    count++;
                    backgroundWorker.ReportProgress(Convert.ToInt32(count / all * 50));
                }
                //更新MD5
                count = 0;
                all = Properties.Settings.Default.BackupDirectoryAddress.Count;
                Properties.Settings.Default.MD5.Clear();
                foreach (string directoryName in Properties.Settings.Default.BackupDirectoryAddress)
                {
                    DirectoryInfo directory = new DirectoryInfo(directoryName);
                    //遍历文件
                    foreach (FileInfo files in directory.GetFiles("*", SearchOption.AllDirectories))
                    {
                        //计算MD5
                        string fileName = files.FullName;
                        string md5 = "";
                        byte[] hashValue;
                        FileStream fileStream = null;
                        System.Security.Cryptography.MD5CryptoServiceProvider md5CSP = new System.Security.Cryptography.MD5CryptoServiceProvider();
                        fileStream = new FileStream(fileName.Replace("\"", ""), FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                        hashValue = md5CSP.ComputeHash(fileStream);
                        fileStream.Close();
                        md5 = BitConverter.ToString(hashValue);
                        md5 = md5.Replace("-", "");
                        Properties.Settings.Default.MD5.Add("{" + fileName + "}" + md5);
                    }
                    count++;
                    backgroundWorker.ReportProgress(Convert.ToInt32(50 + count / all * 50));
                }
                Properties.Settings.Default.Save();
            }
            catch (Exception ex)
            {
                HandlingErrors.ErrorMessage(ex, "请再试一次。");
                HandlingErrors.Record(ex);
            }
        }

        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            recoveryingLabel.Text = Convert.ToInt32(e.ProgressPercentage) + "%";
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            recoveryPictureBox.Visible = true;
            recoveryingLabel.Text = "0%";
            recoveryingLabel.Visible = false;
        }

        private void deletePictureBox_Click(object sender, EventArgs e)
        {
            if (backupListBox.SelectedIndex == -1)
            {
                MessageBox.Show("请选择要删除的备份。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else
            {
                if (MessageBox.Show("您确定要删除下面的备份吗：" + Environment.NewLine + Environment.NewLine + Properties.Settings.Default.BackupAddress + backupListBox.SelectedItem, "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
                {
                    try
                    {
                        Directory.Delete(Properties.Settings.Default.BackupAddress + backupListBox.SelectedItem, true);
                        RefreshInfo();
                    }
                    catch (Exception ex)
                    {
                        HandlingErrors.ErrorMessage(ex, "请手动检查备份是否已被删除，如果没有请再试一次。");
                        HandlingErrors.Record(ex);
                    }
                }
            }
        }

        private void inputPictureBox_Click(object sender, EventArgs e)
        {
            try
            {
                if (OpenFileDialog.ShowDialog() == DialogResult.OK)
                {
                    Compression.DecompressZip(OpenFileDialog.FileName, Properties.Settings.Default.BackupAddress + OpenFileDialog.SafeFileName.Replace(".backup", null));
                    RefreshInfo();
                }
            }
            catch (Exception ex)
            {
                HandlingErrors.ErrorMessage(ex, "请再试一次。");
                HandlingErrors.Record(ex);
            }
        }

        private void outputPictureBox_Click(object sender, EventArgs e)
        {
            if (backupListBox.SelectedIndex == -1)
            {
                MessageBox.Show("请选择要导出的备份。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else
            {
                try
                {
                    SaveFileDialog.FileName = backupListBox.SelectedItem + ".backup";
                    if (SaveFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        Compression.CompressFolder(Properties.Settings.Default.BackupAddress + backupListBox.SelectedItem, SaveFileDialog.FileName, Properties.Settings.Default.ZipLevel);
                    }
                    MessageBox.Show("导出备份成功。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                catch (Exception ex)
                {
                    HandlingErrors.ErrorMessage(ex, "请再试一次。");
                    HandlingErrors.Record(ex);
                }
            }
        }

        private void refreshLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            RefreshInfo();
        }
    }
}
